package net.qhzw.vip.qiyu.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import net.qhzw.vip.qiyu.config.WxPayConfiguration;
import net.qhzw.vip.qiyu.constant.CacheConstants;
import net.qhzw.vip.qiyu.dto.DtsCarTransferPayDto;
import net.qhzw.vip.qiyu.dto.PayParam;
import net.qhzw.vip.qiyu.dto.WeiXinPayRefundParam;
import net.qhzw.vip.qiyu.entity.DtsCarRetreat;
import net.qhzw.vip.qiyu.entity.PayConfig;
import net.qhzw.vip.qiyu.handler.ApiException;
import net.qhzw.vip.qiyu.model.CarRentalCostsVo;
import net.qhzw.vip.qiyu.service.*;
import net.qhzw.vip.qiyu.util.Arith;
import net.qhzw.vip.qiyu.util.IPHelper;
import net.qhzw.vip.qiyu.util.RedisUtils;
import org.apache.axis.utils.ByteArrayOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.math.BigDecimal;


@Service
@Slf4j
public class WeiXinPayServiceImpl implements PayService {

//    @Autowired
//    private WxPayService wxMiniPayService;

//    @Autowired
//    private WxPayConfiguration wxPayConfiguration;

    @Value("${api.domainName}")
    private String domainName;

//    @Value("${spring.profiles.active}")
//    private String active;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private DtsCarRetreatService carRetreatService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private PayConfigService payConfigService;

    @Autowired
    private ShopService shopService;

    @Override
    public String createNative(Long shopId, CarRentalCostsVo carRentalCostsVo) {
        // 支付单号
        String payNo = carRentalCostsVo.getOrderNumber();
        log.info("【支付单号：{}】", payNo);
        String body = "租车 订单号-" + payNo;
        double totalFee = carRentalCostsVo.getTotalRent().doubleValue();
        String notifyUrl = domainName + "/lease/dts/carRental/pay/notify";

        String subMchId = subMchId(shopId);
        PayParam payParam = new PayParam(subMchId, payNo, body, totalFee, notifyUrl);
        String payCode = nativePay(payParam);
        //将支付单信息存入到Redis中
        redisTemplate.boundListOps(CacheConstants.CAR_RENTA_ORDER_CACHE + ":" + payNo).leftPush(JSON.toJSONString(carRentalCostsVo));
        return payCode;
    }

    @Override
    public String carTransPay(Long shopId, DtsCarTransferPayDto payDto) {
        String payNo = payDto.getPayNo();
        String body = "换车维修费";
        double totalFee = payDto.getTotalFee().doubleValue();
        String notifyUrl = domainName + "/lease/dts/carTransfer/pay/notify";
        redisTemplate.boundListOps(CacheConstants.CAR_TRANSFER_ORDER_CACHE + ":" + payNo).leftPush(JSON.toJSONString(payDto.getCarTransferId()));
//            return nativePay(payNo, body, totalFee, notifyUrl);

        PayParam payParam = new PayParam(subMchId(shopId), payNo, body, totalFee, notifyUrl);
        return nativePay(payParam);
    }

    /**
     * 退车支付
     *
     * @param cost
     * @param id
     * @return
     */
    @Override
    public String carCarRetreatPay(Long shopId, Long carRentalId, BigDecimal cost, Long id) {
        String payNo = IdWorker.getId() + "";
        String body = "退车费用";
        double totalFee = Math.abs(cost.doubleValue());
        String notifyUrl = domainName + "/lease/dts/carRetreat/pay/notify";
        //String payCode = nativePay(payNo, body, totalFee, notifyUrl);

        PayParam payParam = new PayParam(subMchId(shopId), payNo, body, totalFee, notifyUrl);
        String payCode = nativePay(payParam);
        DtsCarRetreat carRetreat = new DtsCarRetreat();
        carRetreat.setPayOrder(payNo);
        redisTemplate.boundListOps(CacheConstants.CAR_RETREAT_ORDER_CACHE + ":" + payNo).leftPush(JSON.toJSONString(payNo));
        carRetreatService.update(carRetreat, new LambdaQueryWrapper<DtsCarRetreat>()
                .eq(DtsCarRetreat::getCarRentalId, carRentalId));
        return payCode;
    }

    /**
     * 退款操作
     *
     * @return
     */
    @Override
    public WxPayRefundResult carRetreat(Long shopId, String appId, String refundNo, String transactionId, double totalFee, double refundFee, String notifyUrl, String refundDesc) {
        notifyUrl = domainName + notifyUrl;
//        return refund(refundNo, transactionId, totalFee, refundFee, notifyUrl);
        WeiXinPayRefundParam param = new WeiXinPayRefundParam();
        param.setAppId(appId);
        param.setSubMchId(subMchId(shopId));
        param.setTransactionId(transactionId);
        param.setOutRefundNo(refundNo);
        param.setRefundFee(refundFee);
        param.setTotalFee(totalFee);
        param.setNotifyUrl(notifyUrl);
        param.setRefundDesc(refundDesc);
        return refund(param);
    }

    @Override
    public WxPayMpOrderResult usrRchgGold(Long shopId, String openId, Double amount, String payNo, String notifyUrl) {
        String body = "充值订单号-" + payNo;
//        if (active.equals("dev")) {
//            amount = 0.01;
//        }
        redisTemplate.boundListOps(CacheConstants.USER_ORDER_CACHE + ":" + payNo).leftPush(JSON.toJSONString(payNo));
        PayParam payParam = new PayParam(subMchId(shopId), payNo, body, amount, notifyUrl);
        //return jsapiPay(openId, amount, payNo, body, notifyUrl);
        return jsapiPay(payParam, openId);
    }

    @Override
    public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) {
        try {
            WxPayService wxMiniPayService = WxPayConfiguration.getPayService(new WxPayConfig());
            return wxMiniPayService.parseRefundNotifyResult(xmlData);
        } catch (WxPayException e) {
            String customErrorMsg = e.getCustomErrorMsg();
            throw new ApiException("退款失败，失败信息: " + customErrorMsg);
        }

    }


    /***
     * JSAPI支付
     * @param amount
     * @param payNo
     * @param body
     * @param notifyUrl
     * @return
     */
    /*private WxPayMpOrderResult jsapiPay(String openId, Double amount, String payNo, String body, String notifyUrl) {
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setBody(body);
        orderRequest.setOutTradeNo(payNo);
        orderRequest.setTotalFee((int) Arith.mul(amount, 100));
        orderRequest.setSpbillCreateIp(IPHelper.getIpAddr());
        orderRequest.setNotifyUrl(domainName + notifyUrl);
        orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
        orderRequest.setOpenid(openId);
        WxPayMpOrderResult wxPayMpOrderResult = null;
        try {
            wxPayMpOrderResult = wxMiniPayService.createOrder(orderRequest);
            return wxPayMpOrderResult;
        } catch (WxPayException e) {
            log.error("支付失败：{}", e.getCustomErrorMsg());
            throw new ApiException("支付失败,稍后重试!");
        }
    }*/

    /***
     * @param refundNo 退款订单号
     * @param transactionId 支付成功微信返回的订单号
     * @param totalFee 总金额
     * @param refundFee 退总金额
     * @param notifyUrl 退款成功后调用的url
     * @return
     */
    /*public WxPayRefundResult refund(String refundNo, String transactionId, double totalFee, double refundFee, String notifyUrl) {
        log.info("【退款】：{}");
        WxPayRefundResult wxPayRefundResult = null;
        try {
            WxPayRefundRequest refundRequest = new WxPayRefundRequest();
            refundRequest.setOutRefundNo(refundNo);//退款流水号
            refundRequest.setTransactionId(transactionId);//支付流水号
            if (active.equals("dev")) {
                totalFee = 0.01;
                refundFee = 0.01;
            }
            refundRequest.setRefundFee((int) Arith.mul(refundFee, 100)); //退款金额
            refundRequest.setTotalFee((int) Arith.mul(totalFee, 100)); //金额
            refundRequest.setNotifyUrl(notifyUrl);
            refundRequest.setRefundDesc("剩余退款");
            log.info("【微信退款】request={}", JSON.toJSONString(refundRequest));
            wxPayRefundResult = wxMiniPayService.refund(refundRequest);
            return wxPayRefundResult;
        } catch (WxPayException e) {
            e.printStackTrace();
            throw new ApiException(e.getReturnMsg());
        }
    }*/


    /**
     * 调用统一下单接口，并组装生成支付所需参数对象.
     *
     * @param request 统一下单请求参数
     * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
     */

    public <T> T unifiedOrder(WxPayUnifiedOrderRequest request) {
        log.info("【调用统一下单接口：{}】", JSON.toJSONString(request));
        WxPayConfig wxPayConfig = new WxPayConfig();
        wxPayConfig.setSubMchId(request.getSubMchId());
        WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
        try {
            if ("APP".equals(request.getTradeType())) {//trade_type=APP时
                PayConfig payConfig = payConfigService.getOne(Wrappers.<PayConfig>query().lambda()
                        .eq(PayConfig::getStatus, 1));
                request.setSubAppId(payConfig.getSubAppId());
            }
            if ("NATIVE".equals(request.getTradeType())) {//trade_type=NATIVE时
                request.setProductId(request.getOutTradeNo());
            }
            return wxPayService.createOrder(request);
        } catch (WxPayException e) {
            log.info("【统一下单接口失败：{}】", JSON.toJSONString(e));
            throw new ApiException("下单失败：returnMsg: " + e.getReturnMsg() + " customErrorMsg: " + e.getCustomErrorMsg() + " errCodeDes" + e.getErrCodeDes());
        }
    }

    /**
     * 申请退款
     *
     * @param param
     * @return
     */
    public WxPayRefundResult refund(WeiXinPayRefundParam param) {
        WxPayConfig wxPayConfig = new WxPayConfig();
        wxPayConfig.setAppId(param.getAppId());
        wxPayConfig.setSubMchId(param.getSubMchId());
        WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
        try {
            WxPayRefundRequest request = new WxPayRefundRequest();
            request.setAppid(param.getAppId());
            request.setSubMchId(param.getSubMchId());
            request.setTransactionId(param.getTransactionId());
            request.setOutRefundNo(param.getOutRefundNo());
            request.setRefundFee((int) Arith.mul(param.getRefundFee(), 100));
            request.setTotalFee((int) Arith.mul(param.getTotalFee(), 100));
            request.setNotifyUrl(param.getNotifyUrl());
            request.setRefundDesc(param.getRefundDesc());
            return wxPayService.refund(request);
//            return myWxPayService.refundOrder(request);
        } catch (Exception e) {
            log.error("returnMsg: " + e.getMessage());
            throw new ApiException("申请退款失败");
        }
    }

    /**
     * NATIVE 支付
     *
     * @return
     */
//    public String nativePay(PayParam payParam) {
//        log.info("【调用统一下单接口：{}】", JSON.toJSONString(payParam));
//        WxPayConfig wxPayConfig = new WxPayConfig();
//        wxPayConfig.setSubMchId(payParam.getSubMchId());
//        WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
//        log.info("【wxPayService： {}】", JSON.toJSONString(wxPayService));
//        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
//        request.setSubMchId(payParam.getSubMchId());
//        log.info("【new WxPayUnifiedOrderRequest()。。。。】");
//        request.setTradeType("NATIVE");
//        request.setSubMchId(payParam.getSubMchId());
//        request.setOutTradeNo(payParam.getOutTradeNo());
//        request.setBody(payParam.getBody());
//        request.setTotalFee((int) Arith.mul(payParam.getTotalFee(), 100));
//        request.setNotifyUrl(payParam.getNotifyUrl());
//        log.info("【参数设置ok】");
//        try {
//            log.info("【微信支付调用】");
//            WxPayNativeOrderResult orderResult = wxPayService.createOrder(request);
//            log.info("【微信支付调用成功】");
//            String codeUrl = orderResult.getCodeUrl();
//            return codeUrl;
//        } catch (WxPayException e) {
//            e.printStackTrace();
//        }
//        return null;
//    }


    public String nativePay(PayParam payParam) {
        log.info("【调用统一下单接口：{}】", JSON.toJSONString(payParam));
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        log.info("new WxPayUnifiedOrderRequest............");
        request.setTradeType("NATIVE");
        request.setSubMchId(payParam.getSubMchId());
        request.setOutTradeNo(payParam.getOutTradeNo());
        request.setBody(payParam.getBody());
        request.setTotalFee((int) Arith.mul(payParam.getTotalFee(), 100));
        request.setNotifyUrl(payParam.getNotifyUrl());
        log.info("setSpbillCreateIp............");
        request.setSpbillCreateIp(IPHelper.getIpAddr());
        log.info("【NATIVE 准备支付】：{}");
        WxPayNativeOrderResult orderResult = unifiedOrder(request);
        log.info("【NATIVE 支付成功】：{}", JSON.toJSONString(orderResult));
        String codeUrl = orderResult.getCodeUrl();
        return qrCode(codeUrl);
    }

    /**
     * JSAPI支付
     *
     * @param payParam
     * @param openid
     * @return
     */
    private WxPayMpOrderResult jsapiPay(PayParam payParam, String openid) {
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setTradeType("JSAPI");
        request.setSubMchId(payParam.getSubMchId());
        request.setOutTradeNo(payParam.getOutTradeNo());
        request.setBody(payParam.getBody());
        request.setTotalFee((int) Arith.mul(payParam.getTotalFee(), 100));
        request.setNotifyUrl(domainName + payParam.getNotifyUrl());
        request.setSpbillCreateIp(IPHelper.getIpAddr());
        request.setOpenid(openid);
        WxPayMpOrderResult wxPayMpOrderResult = null;
        try {
            WxPayService wxMiniPayService = WxPayConfiguration.getPayService(new WxPayConfig());
            wxPayMpOrderResult = wxMiniPayService.createOrder(request);
            return wxPayMpOrderResult;
        } catch (WxPayException e) {
            log.error("支付失败：{}", e.getCustomErrorMsg());
            throw new ApiException("支付失败,稍后重试!");
        }
    }


    private String subMchId(Long shopId) {
        return shopService.getWxMchIdById(shopId);
    }

    /**
     * 生成支付二维码
     *
     * @param codeUrl
     * @return
     */
    public String qrCode(String codeUrl) {
        String result = "data:image/jpeg;base64,";
        BufferedImage bufferedImage = QrCodeUtil.generate(codeUrl,
                175,
                175);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
            ImageIO.write(bufferedImage, "png", stream);
            String encode = Base64.encode(stream.toByteArray());
            return result + encode;
        } catch (IOException e) {
            throw new ApiException("二维码生成失败!稍后重试!");
        }
    }


    /**
     * nativePay 支付
     *
     * @param payNo     订单号
     * @param body      商品描述
     * @param totalFee  总金额
     * @param notifyUrl 回调地址
     * @return
     */
    /*private String nativePay(String subMchId, String payNo, String body, double totalFee, String notifyUrl) {
        if (active.equals("dev")) {
            totalFee = 0.01;
        }
        WxPayConfig wxPayConfig = new WxPayConfig();
        wxPayConfig.setSubMchId(subMchId);
        WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        String outTradeNo = payNo;
        String productId = payNo;
        orderRequest.setOutTradeNo(outTradeNo);
        orderRequest.setBody(body);
        orderRequest.setTotalFee((int) Arith.mul(totalFee, 100));
        orderRequest.setNotifyUrl(notifyUrl);
        orderRequest.setTradeType(WxPayConstants.TradeType.NATIVE);
        orderRequest.setSpbillCreateIp(IPHelper.getIpAddr());
        orderRequest.setProductId(productId);
        String code = "";
        WxPayNativeOrderResult orderResult = null;
        try {
            orderResult = wxPayService.createOrder(orderRequest);
            String codeUrl = orderResult.getCodeUrl();
            code = qrCode(codeUrl);
        } catch (WxPayException e) {
            throw new ApiException("支付失败稍后重试！");
        }
        return code;
    }*/








    /*private String nativePay(String payNo, String body, double totalFee, String notifyUrl) {
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        // 支付单号
        orderRequest.setBody(body);
        orderRequest.setOutTradeNo(payNo);
        if (active.equals("dev")) {
            totalFee = 0.01;
        }
        orderRequest.setTotalFee((int) Arith.mul(totalFee, 100));
        orderRequest.setSpbillCreateIp(IPHelper.getIpAddr());
        orderRequest.setNotifyUrl(notifyUrl);
        orderRequest.setTradeType(WxPayConstants.TradeType.NATIVE);
        //orderRequest.setOpenid(dtsUser.getWeixinOpenid());
        orderRequest.setProductId(payNo);
        WxPayNativeOrderResult orderResult = null;
        try {
            orderResult = wxMiniPayService.createOrder(orderRequest);
            String codeUrl = orderResult.getCodeUrl();
            return qrCode(codeUrl);
        } catch (WxPayException e) {
            e.printStackTrace();
            throw new ApiException(e.getMessage());
        }
    }*/


}
